// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/child/child_histogram_message_filter.h"

#include <ctype.h>

#include "base/bind.h"
#include "base/location.h"
#include "base/metrics/histogram_delta_serialization.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/single_thread_task_runner.h"
#include "content/child/child_process.h"
#include "content/common/child_process_messages.h"
#include "ipc/ipc_sender.h"

namespace content {

ChildHistogramMessageFilter::ChildHistogramMessageFilter()
    : sender_(NULL)
    , io_task_runner_(ChildProcess::current()->io_task_runner())
{
}

ChildHistogramMessageFilter::~ChildHistogramMessageFilter()
{
}

void ChildHistogramMessageFilter::OnFilterAdded(IPC::Channel* channel)
{
    sender_ = channel;
}

void ChildHistogramMessageFilter::OnFilterRemoved()
{
}

bool ChildHistogramMessageFilter::OnMessageReceived(
    const IPC::Message& message)
{
    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(ChildHistogramMessageFilter, message)
    IPC_MESSAGE_HANDLER(ChildProcessMsg_SetHistogramMemory,
        OnSetHistogramMemory)
    IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildNonPersistentHistogramData,
        OnGetChildHistogramData)
    IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    return handled;
}

void ChildHistogramMessageFilter::OnSetHistogramMemory(
    const base::SharedMemoryHandle& memory_handle,
    int memory_size)
{
    // This message must be received only once. Multiple calls to create a global
    // allocator will cause a CHECK() failure.
    base::GlobalHistogramAllocator::CreateWithSharedMemoryHandle(memory_handle,
        memory_size);

    base::PersistentHistogramAllocator* global_allocator = base::GlobalHistogramAllocator::Get();
    if (global_allocator)
        global_allocator->CreateTrackingHistograms(global_allocator->Name());
}

void ChildHistogramMessageFilter::OnGetChildHistogramData(int sequence_number)
{
    UploadAllHistograms(sequence_number);
}

void ChildHistogramMessageFilter::UploadAllHistograms(int sequence_number)
{
    // If a persistent allocator is in use, it needs to occasionally update
    // some internal histograms. An upload is happening so this is a good time.
    base::PersistentHistogramAllocator* global_allocator = base::GlobalHistogramAllocator::Get();
    if (global_allocator)
        global_allocator->UpdateTrackingHistograms();

    if (!histogram_delta_serialization_) {
        histogram_delta_serialization_.reset(
            new base::HistogramDeltaSerialization("ChildProcess"));
    }

    std::vector<std::string> deltas;
    // "false" to PerpareAndSerializeDeltas() indicates to *not* include
    // histograms held in persistent storage on the assumption that they will be
    // visible to the recipient through other means.
    histogram_delta_serialization_->PrepareAndSerializeDeltas(&deltas, false);
    sender_->Send(
        new ChildProcessHostMsg_ChildHistogramData(sequence_number, deltas));

#ifndef NDEBUG
    static int count = 0;
    count++;
    LOCAL_HISTOGRAM_COUNTS("Histogram.ChildProcessHistogramSentCount", count);
#endif
}

} // namespace content
